/*
*  Copyright 2019-2020 Zheng Jie
*
*  Licensed under the Apache License, Version 2.0 (the "License");
*  you may not use this file except in compliance with the License.
*  You may obtain a copy of the License at
*
*  http://www.apache.org/licenses/LICENSE-2.0
*
*  Unless required by applicable law or agreed to in writing, software
*  distributed under the License is distributed on an "AS IS" BASIS,
*  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*  See the License for the specific language governing permissions and
*  limitations under the License.
*/
package me.zhengjie.modules.biz.service.impl;

import HslCommunication.Core.Types.OperateResult;
import HslCommunication.Profinet.Siemens.SiemensPLCS;
import HslCommunication.Profinet.Siemens.SiemensS7Net;
import cn.hutool.core.convert.Convert;
import me.zhengjie.modules.biz.domain.*;
import cn.hutool.core.convert.Convert;
import HslCommunication.Core.Types.OperateResult;
import HslCommunication.Profinet.Siemens.SiemensPLCS;
import HslCommunication.Profinet.Siemens.SiemensS7Net;
import me.zhengjie.modules.biz.domain.ExhaustFan;
import me.zhengjie.modules.biz.domain.ExhaustFanLog;
import me.zhengjie.modules.biz.domain.Lab;
import me.zhengjie.modules.biz.repository.ErrorLogRepository;
import me.zhengjie.modules.biz.repository.ExhaustFanLogRepository;
import me.zhengjie.modules.biz.repository.LabRepository;
import me.zhengjie.utils.*;
import lombok.RequiredArgsConstructor;
import me.zhengjie.modules.biz.repository.ExhaustFanRepository;
import me.zhengjie.modules.biz.service.ExhaustFanService;
import me.zhengjie.modules.biz.service.dto.ExhaustFanDto;
import me.zhengjie.modules.biz.service.dto.ExhaustFanQueryCriteria;
import me.zhengjie.modules.biz.service.mapstruct.ExhaustFanMapper;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import springfox.documentation.swagger2.mappers.CompatibilityModelMapper;
import springfox.documentation.swagger2.mappers.ModelMapper;

import java.lang.System;
import java.util.*;
import java.io.IOException;
import java.util.stream.Collectors;
import javax.servlet.http.HttpServletResponse;

/**
* @website https://eladmin.vip
* @description 服务实现
* @author Admin
* @date 2023-02-17
**/
@Service
@RequiredArgsConstructor
public class ExhaustFanServiceImpl implements ExhaustFanService {

    private final ExhaustFanRepository exhaustFanRepository;
    private final ExhaustFanMapper exhaustFanMapper;
    private final LabRepository labRepository;
    private final ExhaustFanLogRepository exhaustFanLogRepository;
    private final ErrorLogRepository errorLogRepository;
    private final CompatibilityModelMapper compatibilityModelMapper;
    private final ModelMapper modelMapper;

    @Override
    public Map<String,Object> queryAll(ExhaustFanQueryCriteria criteria, Pageable pageable){
        Page<ExhaustFan> page = exhaustFanRepository.findAll((root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root,criteria,criteriaBuilder),pageable);
        Page<ExhaustFanDto> dto = page.map(exhaustFanMapper::toDto);
        List<ExhaustFanDto> resultDto = dto.getContent();
        for (ExhaustFanDto exhaustFanDto:resultDto) {
            if (Objects.nonNull(exhaustFanDto.getLabId())) {
                Lab lab = labRepository.findById(exhaustFanDto.getLabId()).orElseGet(Lab::new);
                if (Objects.nonNull(lab.getId())) {
                    exhaustFanDto.setLabName(lab.getName());
                }
            }
        }
        return PageUtil.toPage(dto);
    }

    @Override
    public List<ExhaustFanDto> queryAll(ExhaustFanQueryCriteria criteria){
        List<ExhaustFan> exhaustFanList = exhaustFanRepository.findAll((root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root,criteria,criteriaBuilder));
        List<ExhaustFanDto> exhaustFanDtoList = exhaustFanMapper.toDto(exhaustFanList);
        for (ExhaustFanDto exhaustFanDto : exhaustFanDtoList) {
            if (Objects.nonNull(exhaustFanDto.getLabId())) {
                Lab lab = labRepository.findById(exhaustFanDto.getLabId()).orElseGet(Lab::new);
                if (Objects.nonNull(lab.getId())) {
                    exhaustFanDto.setLabName(lab.getName());
                }
            }
        }
        return exhaustFanDtoList;
    }

    @Override
    @Transactional
    public ExhaustFanDto findById(Integer id) {
        ExhaustFan exhaustFan = exhaustFanRepository.findById(id).orElseGet(ExhaustFan::new);
        ValidationUtil.isNull(exhaustFan.getId(),"ExhaustFan","id",id);
        return exhaustFanMapper.toDto(exhaustFan);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ExhaustFanDto create(ExhaustFan resources) {
        return exhaustFanMapper.toDto(exhaustFanRepository.save(resources));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void update(ExhaustFan resources) {
        ExhaustFan exhaustFan = exhaustFanRepository.findById(resources.getId()).orElseGet(ExhaustFan::new);
        ValidationUtil.isNull( exhaustFan.getId(),"ExhaustFan","id",resources.getId());
        exhaustFan.copy(resources);
        exhaustFanRepository.save(exhaustFan);
    }

    @Override
    public void deleteAll(Integer[] ids) {
        for (Integer id : ids) {
            exhaustFanRepository.deleteById(id);
        }
    }

    @Override
    public void download(List<ExhaustFanDto> all, HttpServletResponse response) throws IOException {
        List<Map<String, Object>> list = new ArrayList<>();
        for (ExhaustFanDto exhaustFan : all) {
            Map<String,Object> map = new LinkedHashMap<>();
            map.put("名称", exhaustFan.getName());
            map.put("排风柜ip", exhaustFan.getIp());
            map.put("地址", exhaustFan.getAddress());
            map.put("实验室", exhaustFan.getLabName());
            map.put("面风速", exhaustFan.getSurfaceWindSpeed());
            map.put("排风量", exhaustFan.getExhaustAirRate());
            map.put("风量差量", exhaustFan.getAirVolumeDifference());
            String states = "";
            switch (exhaustFan.getStatus()) {
                case 0:
                    states = "正常";
                    break;
                case 1:
                    states = "故障";
                    break;
            }
            map.put("状态", states);
            map.put("风量信息", exhaustFan.getMessage());
            list.add(map);
        }
        FileUtil.downloadExcel(list, response);
    }

    @Override
    public List<ExhaustFanDto> queryExhaustFanFloor(Integer floor) {
        List<ExhaustFanDto> list = exhaustFanMapper.toDto(exhaustFanRepository.findByFloor(floor));
        for (ExhaustFanDto exhaustFanDto:list) {
            Lab lab = labRepository.findById(exhaustFanDto.getLabId()).orElseGet(Lab::new);
            exhaustFanDto.setLabName(lab.getName());
        }
        return list;
    }


    @Scheduled(cron = "0 0 * * * ?")
    @Override
    public void queryDataFromPLC() {
        List<ExhaustFan> exhaustFanList = exhaustFanRepository.findAll();
        if (exhaustFanList.size() < 1) {
            return;
        }
        String ip;
        String vocIp;
        String address;
        int intData;
        byte byteData;
        float floatData;
        for (ExhaustFan exhaustFan : exhaustFanList) {
            ExhaustFanLog exhaustFanLog = new ExhaustFanLog();

            if (exhaustFan.getIp() != null) {
                ip = exhaustFan.getIp();

                SiemensS7Net siemensTcpNet = new SiemensS7Net(SiemensPLCS.S200, ip);
                OperateResult connect = siemensTcpNet.ConnectServer( );
                if (connect.IsSuccess)
                {
                    if (exhaustFan.getAddress() != null) {
                        address = exhaustFan.getAddress();
                        byteData = siemensTcpNet.ReadByte(address).Content;
                        intData = byteData & 1;
                        exhaustFan.setTransducerIsOpen(intData);
                        exhaustFanLog.setTransducerIsOpen(intData);
                    }
                    if (exhaustFan.getFaultAddress() != null) {
                        address = exhaustFan.getFaultAddress();
                        byteData = siemensTcpNet.ReadByte(address).Content;
                        intData = byteData & 1;
                        exhaustFan.setFaultIndication(intData);
                        exhaustFanLog.setFaultIndication(intData);
                    }
                    if (exhaustFan.getFrequencyAddress() != null) {
                        address = exhaustFan.getFrequencyAddress();
                        floatData = siemensTcpNet.ReadFloat(address).Content;
                        exhaustFan.setOperatingFrequency(floatData);
                        exhaustFanLog.setOperatingFrequency(floatData);
                    }
                    if (exhaustFan.getVoltageAddress() != null) {
                        address = exhaustFan.getVoltageAddress();
                        floatData = siemensTcpNet.ReadFloat(address).Content;
                        exhaustFan.setSupplyVoltage(floatData);
                        exhaustFanLog.setSupplyVoltage(floatData);
                    }
                    if (exhaustFan.getSpeedAddress() != null) {
                        address = exhaustFan.getSpeedAddress();
                        floatData = siemensTcpNet.ReadFloat(address).Content;
                        exhaustFan.setMotorSpeed(floatData);
                        exhaustFanLog.setMotorSpeed(floatData);
                    }
                }
                siemensTcpNet.ConnectClose();
            }

            if (exhaustFan.getVocIp() != null) {
                vocIp = exhaustFan.getVocIp();
                   SiemensS7Net siemensTcpNet = new SiemensS7Net(SiemensPLCS.S200, vocIp);
                OperateResult connect = siemensTcpNet.ConnectServer( );
                if (connect.IsSuccess)
                {
                    if (exhaustFan.getVocAddress() != null) {
                        address = exhaustFan.getVocAddress();
                        floatData = siemensTcpNet.ReadFloat(address).Content;
                        if (Objects.nonNull(floatData)) {
                            exhaustFan.setVoc(floatData);
                            exhaustFanLog.setVoc(floatData);
                        }
                    }
                    if (exhaustFan.getActiveCarbonAlarmAddress() != null) {
                        address = exhaustFan.getActiveCarbonAlarmAddress();
                        byteData = siemensTcpNet.ReadByte(address).Content;
                        intData = byteData & 1;
                        if (Objects.equals(intData, 1)) {
                            exhaustFanLog.setStatus(1);
                        }
                    }
                }
                siemensTcpNet.ConnectClose();
            }

            exhaustFanRepository.save(exhaustFan);

            exhaustFanLog.setExhaustFanId(exhaustFan.getId());
            exhaustFanLog.setLabId(exhaustFan.getLabId());
            exhaustFanLogRepository.save(exhaustFanLog);
        }
    }

    @Scheduled(cron = "0 0 */6 * * ?")
    public void queryDataFromPLCLog() {
        List<ExhaustFan> exhaustFanList = exhaustFanRepository.findAll();
        if (exhaustFanList.size() < 1) {
            return;
        }
        String ip;
        String vocIp;
        String address;
        int intData;
        byte byteData;
        float floatData;
        for (ExhaustFan exhaustFan : exhaustFanList) {
            ExhaustFanLog exhaustFanLog = new ExhaustFanLog();

            if (exhaustFan.getIp() != null) {
                ip = exhaustFan.getIp();

                SiemensS7Net siemensTcpNet = new SiemensS7Net(SiemensPLCS.S200, ip);
                OperateResult connect = siemensTcpNet.ConnectServer( );
                if (connect.IsSuccess)
                {
                    if (exhaustFan.getAddress() != null) {
                        address = exhaustFan.getAddress();
                        byteData = siemensTcpNet.ReadByte(address).Content;
                        intData = byteData & 1;
                        exhaustFan.setTransducerIsOpen(intData);
                        exhaustFanLog.setTransducerIsOpen(intData);
                    }
                    if (exhaustFan.getFaultAddress() != null) {
                        address = exhaustFan.getFaultAddress();
                        byteData = siemensTcpNet.ReadByte(address).Content;
                        intData = byteData & 1;
                        exhaustFanLog.setFaultIndication(intData);
                    }
                    if (exhaustFan.getFrequencyAddress() != null) {
                        address = exhaustFan.getFrequencyAddress();
                        floatData = siemensTcpNet.ReadFloat(address).Content;
                        exhaustFanLog.setOperatingFrequency(floatData);
                    }
                    if (exhaustFan.getVoltageAddress() != null) {
                        address = exhaustFan.getVoltageAddress();
                        floatData = siemensTcpNet.ReadFloat(address).Content;
                        exhaustFanLog.setSupplyVoltage(floatData);
                    }
                    if (exhaustFan.getSpeedAddress() != null) {
                        address = exhaustFan.getSpeedAddress();
                        floatData = siemensTcpNet.ReadFloat(address).Content;
                        exhaustFanLog.setMotorSpeed(floatData);
                    }
                }
                siemensTcpNet.ConnectClose();
            }

            if (exhaustFan.getVocIp() != null) {
                vocIp = exhaustFan.getVocIp();
                SiemensS7Net siemensTcpNet = new SiemensS7Net(SiemensPLCS.S200, vocIp);
                OperateResult connect = siemensTcpNet.ConnectServer( );
                if (connect.IsSuccess)
                {
                    if (exhaustFan.getVocAddress() != null) {
                        address = exhaustFan.getVocAddress();
                        floatData = siemensTcpNet.ReadFloat(address).Content;
                        exhaustFanLog.setVoc(floatData);
                    }
                    if (exhaustFan.getActiveCarbonAlarmAddress() != null) {
                        address = exhaustFan.getActiveCarbonAlarmAddress();
                        byteData = siemensTcpNet.ReadByte(address).Content;
                        intData = byteData & 1;
                        if (Objects.equals(intData, 1)) {
                            exhaustFanLog.setStatus(1);
                        }
                    }
                }
                siemensTcpNet.ConnectClose();
            }

            exhaustFanLog.setExhaustFanId(exhaustFan.getId());
            exhaustFanLog.setLabId(exhaustFan.getLabId());
            exhaustFanLogRepository.save(exhaustFanLog);
        }
    }

    @Scheduled(cron = "0 0 * * * ?")
    public void queryAlarmDataFromPLC() {
        List<ExhaustFan> exhaustFanList = exhaustFanRepository.findAll();
        if (exhaustFanList.size() < 1) {
            return;
        }

        String vocIp;
        String address;
        int intData;
        byte byteData;
        for (ExhaustFan exhaustFan : exhaustFanList) {
            if (exhaustFan.getVocIp() != null) {
                vocIp = exhaustFan.getVocIp();
                SiemensS7Net siemensTcpNet = new SiemensS7Net(SiemensPLCS.S200, vocIp);
                OperateResult connect = siemensTcpNet.ConnectServer( );
                if (connect.IsSuccess)
                {
                    if (exhaustFan.getActiveCarbonAlarmAddress() != null) {
                        address = exhaustFan.getActiveCarbonAlarmAddress();
                        byteData = siemensTcpNet.ReadByte(address).Content;
                        intData = byteData & 1;
                        if (Objects.equals(intData, 1)) {
                            Lab lab = labRepository.findById(exhaustFan.getLabId()).orElseGet(Lab::new);
                            ValidationUtil.isNull( exhaustFan.getLabId(),"Lab","id",lab.getId());
                            ErrorLog errorLog = new ErrorLog();
                            errorLog.setName(exhaustFan.getName());
                            errorLog.setPosition(lab.getName());
                            errorLog.setErrorCode("排风机故障");
                            errorLog.setDec("排风机故障");
                            errorLog.setType(2);
                            errorLog.setValue(2f);
                            errorLog.setFloor(lab.getFloor());
                            errorLogRepository.save(errorLog);
                        }
                    }
                }
                siemensTcpNet.ConnectClose();
            }
        }
    }

    @Override
    public Map<Object, Object> queryStatus() {
        Map<Object, Object> list = exhaustFanLogRepository.queryStatus().stream().collect(Collectors.toMap(t->t.get("flag"), t->t.get("count")));
        return list;
    }
}
